@isTest
private class UT_Calculations_ModelValidator {
    
    static testMethod void SimplestTestCase() 
    {
        ENT_2__Support_Program__c sp = new ENT_2__Support_Program__c( 
             Name='TestSP',
             P1__c = 'xyz',
             RecordTypeId=RT.MASPId
             );
        insert sp;
    }
    

    //
    // These tests set up a plausible SP/Entitlement pair, and then assert the 
    // calculated times.
    //
    
    static string[] orgStatuses = CaseStdFieldControl.GetAllPicklistValuesFromCase('STATUS');
    static string[] orgPriorities = CaseStdFieldControl.GetAllPicklistValuesFromCase('PRIORITY');
/*    
    static boolean orgPreconditionsSatisfied() {
        if (orgStatuses==null) orgStatuses = CaseTriggerHelpers.GetAllPicklistValuesFromCase('STATUS');
        if (orgPriorities==null) orgPriorities = CaseTriggerHelpers.GetAllPicklistValuesFromCase('PRIORITY');
        
        if (orgStatuses.size() < 2) {
            System.debug('WARNING:  Skipping test because org has <2 possible Statuses for Case');
            return false;
        }
        if (orgPriorities.size() < 1) {
            System.debug('WARNING:  Skipping test because org has no possible Priorities for Case');
            return false;
        }
        
        return true;
    }
*/    
    // Test starting in a running status
    public static testMethod void testRecalcStartingS1P1(){
//        if (!orgPreconditionsSatisfied()) { System.debug('Aborting b/c org fails preconditions'); return; }  
        
        InitOrgStoppedStatuses();  // sets S2 to be the only stopped
        TestObjects pair = CreateTestScenarioObjects( 
            new Integer[]{1,2,3,  5,6,7,  10,11,12,  15,16,17,  20,21,22}, null );
        
        // Try a test case with intial status = S1, priority = P1
        Case c = makeCase(pair,orgStatuses[0],orgPriorities[0],null);  // TODO:  pass expected vals
        testCyclePris(c,orgPriorities,null);  // cycles through the other priorities
        // TODO:  pass expected vals
        
        // Switch to stopped status and repeat 
        c.Status = orgStatuses[1]; update c; 
        testCyclePris(c,orgPriorities,null);  // TODO:  pass expected vals
    }
    
    // Test starting in a stopped Status
    public static testMethod void testRecalcStartingS2P1(){
//        if (!orgPreconditionsSatisfied()) { System.debug('Aborting b/c org fails preconditions'); return; }  
        
        InitOrgStoppedStatuses(); // sets S2 to be the only stopped
        TestObjects pair = CreateTestScenarioObjects( 
            new Integer[]{1,2,3,  5,6,7,  10,11,12,  15,16,17,  20,21,22}, null );  // TODO:  use non-default BH
        
        // Try a test case with intial status = S1, priority = P1
        Case c = makeCase(pair,orgStatuses[1],orgPriorities[0],null);  // TODO:  pass expected vals
        testCyclePris(c,orgPriorities,null);  // cycles through the other priorities
        // TODO:  pass expected vals
        
        // Switch to running status and repeat 
        c.Status = orgStatuses[0]; update c; 
        testCyclePris(c,orgPriorities,null);  // TODO:  pass expected vals
    }
    
    static Case makeCase(TestObjects pair,string initialStatus,string initialPri,String[] expectedFieldVals) {
        Case c = new Case( Entitlement__c=pair.e.Id, Status=initialStatus, Priority = initialPri );
        insert c;
        // TODO:  assert expectedFieldVals here
        
        return c;
    }
    static void testCyclePris(Case c,string[] prioritiesArr,String[] expectedFieldVals) {
        for(string p : prioritiesArr) {
            string oldP = c.Priority;
            c.Priority = p;
            update c;
            // TODO:  assert correct values here
            System.debug('MODEL TEST ACTION:  priority changed from ' + oldP + ' to ' + p);
            //System.debug('CASE FIELDS:  EFR='  + c.Entitled_First_Response + ', ERT='  + c.Entitled_Resolve__c);
        }

    }
    
    
    //
    // Sets up a plausible SP/Entitlement pair with sensible mappings for
    // this org.
    //
    class TestObjects {
        public TestObjects (Support_Program__c sp,Entitlement__c e) {
            this.sp = sp;
            this.e = e;
        }
        public Support_Program__c sp;
        public Entitlement__c e;
    }
    static TestObjects CreateTestScenarioObjects(Integer[] timesList, Id EntBusinessHoursId) {
        // timesList vector is like this:  (P1.EFR, P1.EW, P1.ERT, ..., P5.EFR, P5.EW, P5.ERT)
        System.assert(timesList.size() == 15);
        System.assert(EntBusinessHoursId==null);  // Cant set this for some reason
        
        String[] pri = CaseStdFieldControl.GetAllPicklistValuesFromCase('PRIORITY');
        Support_Program__c sp = new Support_Program__c( Name='TestSP',
             P1__c = pri[0], RecordTypeId=RT.MASPId
             );
        insert sp;
        Entitlement__c e = new Entitlement__c( Name='TestEnt', Support_Program__c=sp.Id,Business_Hours__c=UT_SObjectFactory.DefBHId );
        //e.BusinessHoursId = EntBusinessHoursId;  // TODO:  why can't we set this value here?
        insert e;
        return new TestObjects (sp,e);
    }
    
    //
    // Sets S2 (the second Status in this org) as a clock stop; all others are running clock.  
    // (NB:  database changes get rolled back automatically after tests.)
    //
    static void InitOrgStoppedStatuses() {
        
        // Flush the list of stop statuses
        for(Stop_Status__c ss:[select Id from Stop_Status__c]) {
            delete ss;
        }
        
        String[] statusesArr = CaseStdFieldControl.GetAllPicklistValuesFromCase('STATUS');
        if (statusesArr.size() == 0) {
            // Nothing we can do about this, but do note it
            System.debug('WARNING:  Organization has no Case Status values, or they were unreadable during test');
            return;
        } else if (statusesArr.size() == 1) {
            System.debug('WARNING:  Organization has only one Case Status value, so we will assume it is a RUNNING state ');
            return;
        } else {
            // Create one stop status (the first Case priority)
            Stop_Status__c ss = new Stop_Status__c(Name=statusesArr[1]);
            insert ss;
            for (string stat : statusesArr) {
                if (stat == ss.Name) {
                    System.debug('MODEL ASSUMPTION:  Case Status ' + ss.Name + ' is STOPPED status.');
                } else {
                    System.debug('MODEL ASSUMPTION:  Case Status ' + ss.Name + ' is RUNNING status.');
                }
            }
        }
    }    
}